﻿using InChatter.Client.Service;
using InChatter.Client.Service.ChatServer;
using InChatter.Client.WPFClient.Utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace InChatter.Client.WPFClient.ViewModel
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        #region Property
        private ObservableCollection<ClientContext> _clients;
        /// <summary>
        /// All Clients
        /// </summary>
        public ObservableCollection<ClientContext> Clients
        {
            get { return _clients; }
            set
            {
                _clients = value;
                OnPropertyChanged("Clients");
            }
        }

        private ObservableCollection<MessageCategory> _messageTypeList;
        /// <summary>
        /// Message category list
        /// </summary>
        public ObservableCollection<MessageCategory> MessageTypeList
        {
            get { return _messageTypeList; }
            set
            {
                _messageTypeList = value;
                OnPropertyChanged("MessageTypeList");
            }
        }

        private IList<InChatterMessage> _allMessageInfos;
        /// <summary>
        /// All history messages
        /// </summary>
        public IList<InChatterMessage> AllMessageInfos
        {
            get
            {
                return _allMessageInfos;
            }
            set
            {
                _allMessageInfos = value;
                OnPropertyChanged("MessageInfos");
            }
        }

        private ObservableCollection<InChatterMessage> _messageItems;
        public ObservableCollection<InChatterMessage> MessageItems
        {
            get { return _messageItems; }
            set
            {
                _messageItems = value;
                OnPropertyChanged("MessageItems");
            }
        }

        private ClientContext m_SelectedClient;
        /// <summary>
        /// the choosen client
        /// </summary>
        public ClientContext SelectedClient
        {
            get { return m_SelectedClient; }
            set
            {
                if (value != null && value.Count > 0)
                {
                    ChatMsgCenter.Instance.OnTypeChanged("msg", value.ClientId);
                }
                m_SelectedClient = value;
                OnPropertyChanged("SelectedClient");
                if (value != null)
                {
                    ReLoadClientData();
                }
            }
        }

        private MessageCategory m_SelectedType;
        /// <summary>
        /// Selected message category
        /// </summary>
        public MessageCategory SelectedType
        {
            get { return m_SelectedType; }
            set
            {
                if (value != null)
                {
                    if (value.Count > 0)
                    {
                        ChatMsgCenter.Instance.OnTypeChanged(value.Type, "");
                    }
                }
                m_SelectedType = value;
                OnPropertyChanged("SelectedType");
                if (value != null)
                {
                    ReLoadMessageData(m_SelectedType);
                }
            }
        }

        private Visibility m_clientVisibility;
        /// <summary>
        /// 
        /// </summary>
        public Visibility ClientVisibility
        {
            get { return m_clientVisibility; }
            set
            {
                m_clientVisibility = value;
                OnPropertyChanged("ClientVisibility");
            }
        }

        private Visibility m_WindowStatus = Visibility.Collapsed;
        /// <summary>
        /// 
        /// </summary>
        public Visibility WindowStatus
        {
            get
            {
                return m_WindowStatus;
            }
            set
            {
                m_WindowStatus = value;
                OnPropertyChanged("WindowStatus");
            }
        }

        private Visibility _SendBoxVisibility;

        public Visibility SendBoxVisibility
        {
            get { return _SendBoxVisibility; }
            set
            {
                _SendBoxVisibility = value;
                OnPropertyChanged("SendBoxVisibility");
            }
        }

        public DelegateCommand<string> DeleteMsgCommand { private set; get; }
        public DelegateCommand<string> SendMsgCommand { private set; get; }

        public Action MessageItemChanged;
        public void OnMesssageItemChanged()
        {
            if (MessageItemChanged != null)
            {
                MessageItemChanged();
            }
        }

        public Action RequestToChat;
        public void OnRequestToChat()
        {
            if (RequestToChat != null)
            {
                RequestToChat();
            }
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="regionManager"></param>
        /// <param name="container"></param>
        public MainWindowViewModel()
        {
            InitializeCommand();
            LoadData();
            LoadAllClients();
            InitializeEvent();
            MessageItems = new ObservableCollection<InChatterMessage>();
        }

        private void InitializeEvent()
        {
            ChatMsgCenter.Instance.MessagePoolReceivedNew += new Action<InChatterMessage>(Instance_MessagePoolReceivedNew);
            ChatMsgCenter.Instance.ClientLogin += new Action<string>(Instance_ClientLogin);
            ChatMsgCenter.Instance.MessageIgnored += new Action<InChatterMessage>(Instance_MessageIgnored);
            ChatMsgCenter.Instance.RequestToRead += new Action<IEnumerable<InChatterMessage>>(Instance_RequestToRead);
            ChatMsgCenter.Instance.MessageReadDirectly = new Func<InChatterMessage, bool>(Instance_MessageReadDirectly);
        }

        private void Instance_MessagePoolReceivedNew(InChatterMessage msg)
        {
            var category = this.MessageTypeList.Single(p => p.Type == msg.Type);
            if (msg.Type == "msg")
            {
                var employee = Clients.Single(p => p.ClientId == msg.SenderID);
                employee.Count++;
            }
            category.Count++;
        }

        private void Instance_MessageIgnored(InChatterMessage msg)
        {
            var category = this.MessageTypeList.Single(p => p.Type == msg.Type);
            if (msg.Type == "msg")
            {
                var employee = Clients.Single(p => p.ClientId == msg.SenderID);
                employee.Count--;
            }
            category.Count--;
            //Message already exists then return
            if (this.AllMessageInfos.Count(mi => mi.ID == msg.ID) > 0)
            {
                return;
            }
            else
            {
                this.AllMessageInfos.Add(msg);
            }
        }

        private void ReadMessage(MessageCategory category, InChatterMessage msg)
        {
            category.Count--;
            this.AllMessageInfos.Add(msg);
            this.MessageItems.Add(msg);
            OnMesssageItemChanged();
            ChatMsgCenter.Instance.OnMessageRead(msg);
        }

        private void Instance_RequestToRead(IEnumerable<InChatterMessage> msg)
        {
            if (msg == null || msg.Count() == 0)
            {
                return;
            }
            foreach (var item in msg)
            {
                this.AllMessageInfos.Add(item);
            }

            InChatterMessage mi = msg.First();
            var category = this.MessageTypeList.Single(p => p.Type == mi.Type);
            category.Count -= msg.Count();
            SelectedType = category;
            if (mi.Type == "msg")
            {
                SelectedClient = Clients.Single(p => p.ClientId == mi.SenderID);
            }
            OnRequestToChat();
        }

        private void Instance_ClientLogin(string ids)
        {
            SetLogonState(ids);
        }

        private bool Instance_MessageReadDirectly(InChatterMessage msg)
        {
            if (msg.Type == "logon")
            {
                SetLogonState(msg.Content);
                return true;
            }
            else if (msg.Type == "logoff")
            {
                SetLogoffState(msg.Content);
                return true;
            }
            if (SelectedType != null && SelectedType.Type == msg.Type)
            {
                if (msg.Type != "msg")
                {
                    this.AllMessageInfos.Add(msg);
                    this.MessageItems.Add(msg);
                    OnMesssageItemChanged();
                    return true;
                }
                else
                {
                    if (SelectedClient != null && SelectedClient.ClientId == msg.SenderID)
                    {
                        this.AllMessageInfos.Add(msg);
                        this.MessageItems.Add(msg);
                        OnMesssageItemChanged();
                        return true;
                    }
                }
            }
            return false;
        }

        private void InitializeCommand()
        {
            DeleteMsgCommand = new DelegateCommand<string>((str) =>
            {
                DataHelper.Delete(str);
                var mi = AllMessageInfos.First(p => p.ID == str);
                AllMessageInfos.Remove(mi);
                MessageItems.Remove(mi);
            });
            SendMsgCommand = new DelegateCommand<string>((content) =>
            {
                char[] trimChar = { '\r', '\n' };
                content = content.TrimEnd(trimChar);

                if (content == "")
                {
                    return;
                }
                InChatterMessage msg = new InChatterMessage()
                {
                    ID=Guid.NewGuid().ToString(),
                    Content = content,
                    SenderID = ClientContext.Current.ClientId,
                    SenderName = ClientContext.Current.ClientName,
                    SendTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                };
                if (SelectedType.Type != null && SelectedType.Type == "notice")
                {
                    msg.ReceiverID = "";
                    msg.ReceiverName = "";
                    msg.Type = "notice";
                }
                else
                {
                    if (SelectedClient == null)
                    {
                        return;
                    }
                    msg.ReceiverID = SelectedClient.ClientId;
                    msg.ReceiverName = SelectedClient.ClientName;
                    msg.Type = "msg";
                }
                msg.IsRead = true;
                ChatMsgCenter.Instance.SendMsg(msg);
                this.AllMessageInfos.Add(msg);
                MessageItems.Add(msg);
                OnMesssageItemChanged();
            });
        }

        public void LoadData()
        {
            ThreadPool.QueueUserWorkItem((obj) =>
            {
                AllMessageInfos = new ObservableCollection<InChatterMessage>(ChatMsgCenter.Instance.ReadAllMessage());
                var result = SetTypeList();
                Application.Current.Dispatcher.Invoke(new Action(() =>
                {
                    MessageTypeList = new ObservableCollection<MessageCategory>(result);
                    ClientVisibility = Visibility.Collapsed;
                    //SelectedType = MessageTypeList.First();
                }), null);
            });
        }

        /// <summary>
        /// Load all clients
        /// </summary>
        void LoadAllClients()
        {
            Clients = new ObservableCollection<ClientContext>();
            IList<ClientContext> result = (from item in ClientContext.AllClients
                                           where item.ClientId != ClientContext.Current.ClientId
                                           orderby item.ClientName
                                           select item).ToList();
            foreach (var client in result)
            {
                Clients.Add(client);
            }
        }

        public List<MessageCategory> SetTypeList()
        {
            List<MessageCategory> list = new List<MessageCategory>();
            MessageCategory category = new MessageCategory()
            {
                Id = "",
                CategoryName = InChatter.Localization.Properties.Resources.Notice,
                Type = "notice",
                Count = 0,
            };
            list.Add(category);
            category = new MessageCategory()
            {
                Id = "",
                CategoryName = InChatter.Localization.Properties.Resources.Chat,
                Type = "msg",
                Count = 0,
            };
            list.Add(category);
            return list;
        }

        /// <summary>
        /// Load Message History by message category
        /// </summary>
        /// <param name="TypeStr"></param>
        private void ReLoadMessageData(MessageCategory category)
        {
            if (SelectedType.Type == "msg")
            {
                ClientVisibility = Visibility.Visible;
                ReLoadClientData();
            }
            else
            {
                MessageItems.Clear();
                foreach (var item in this.AllMessageInfos.Where(p => p.Type == SelectedType.Type).OrderBy(p => p.SendTime).ToList())
                {
                    MessageItems.Add(item);
                }
                ClientVisibility = Visibility.Collapsed;
                OnMesssageItemChanged();
            }
        }

        private void ReLoadClientData()
        {
            if (SelectedClient == null)
            {
                MessageItems.Clear();
                return;
            }
            var result = this.AllMessageInfos.Where(p => p.Type == SelectedType.Type &&
                   (p.SenderID == SelectedClient.ClientId || p.ReceiverID == SelectedClient.ClientId)).OrderBy(p => p.SendTime).ToList();
            MessageItems.Clear();
            foreach (var item in result)
            {
                MessageItems.Add(item);
            }
            OnMesssageItemChanged();
        }

        internal void SetLogonState(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return;
            }
            string[] array = id.Split(',');
            foreach (var item in Clients)
            {
                if (array.Contains(item.ClientId))
                {
                    item.IsOnline = true;
                }
            }
        }

        internal void SetLogoffState(string p)
        {
            if (string.IsNullOrEmpty(p))
            {
                return;
            }
            foreach (var item in Clients)
            {
                if (p == item.ClientId)
                {
                    item.IsOnline = false;
                    break;
                }
            }
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}
